---@diagnostic disable: assign-type-mismatch
local division = require 'division'
local padding = require 'padding'
local rect = require 'rect'
local vec2 = require 'vec2'
local color = require 'color'

local list = require 'views.list'

local ui = {}

---@type fun(options: { align: vec2, child: view }): aligned
ui.aligned = require 'views.aligned'
---@type fun(options: { color: vec4, border_radius: border_radius }): decorated_box
ui.decorated_box = require 'views.decorated_box'

---@type fun(options: { direction: layout_direction, children: view[] }): list
ui.list = list
ui.layout_direction = list.layout_direction

---@type fun(options: { padding: padding, child: view }): padded
ui.padded = require 'views.padded'
---@type fun(options: { width: number, height: number, child: view }): sized_box
ui.sized_box = require 'views.sized_box'
---@type fun(options: { children: view[] }): stack
ui.stack = require 'views.stack'
---@type fun(options: { text: string, font_size: number, color: vec4 }): text
ui.text = require 'views.text'
---@type fun(builder: fun(): view): view_builder
ui.view_builder = require 'views.view_builder'

---@param table { child : view?, margin: padding?, padding: padding?, background_color: vec4?, border_radius: border_radius? }
---@return view
function ui.container(table)
    local background = ui.decorated_box {
        color = table.background_color or color.WHITE,
        border_radius = table.border_radius
    }
    local result
    if table.child then
        local child = table.padding ~= nil
            and padding { child = table.child, padding = table.padding }
            or table.child

        result = ui.stack {
            children = {
                background,
                child
            }
        }
    else
        result = background
    end

    return table.margin ~= nil
        and padding { child = result, padding = table.margin }
        or result
end

---@private
---@type view
ui.__root_view = nil

---@private
---@type view.renderer
ui.__root_view_renderer = nil

local screen_size = division:screen_size()
local force_rebuild_ui = false

local function rerender(screen_size)
    local screen_rect = rect.from_bottom_left(vec2(0), screen_size)
    ui.__root_view_renderer:render(screen_rect, ui.__root_view)
end

local function on_update()
    local curr_screen_size = division:screen_size()
    local rebuild_ui = force_rebuild_ui or curr_screen_size ~= screen_size
    if ui.__root_view_renderer and rebuild_ui then
        screen_size = curr_screen_size
        rebuild_ui = false

        rerender(screen_size)
    end
end

local function on_destroy()
    if ui.__root_view_renderer then
        ui.__root_view_renderer:destroy()
    end
end

---Initialize ui drawing
---@param root_view view
function ui.run(root_view)
    assert(root_view)

    on_destroy()

    ui.__root_view = root_view
    ui.__root_view_renderer = root_view:create_renderer_instance()
    rerender(screen_size)
end

function ui.rebuild()
    force_rebuild_ui = true
end

division:add_update_listener(on_update)
division:add_destroy_listener(on_destroy)

return ui
